----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    10:14:28 11/14/2010 
-- Design Name: 
-- Module Name:    testUART - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity MAIN is
    Port ( Serial_Out : out  STD_LOGIC;
			  Serial_In : in STD_LOGIC;
			  Clock_IN : in  STD_LOGIC;
			  LED		: out std_logic_vector(7 downto 0);
			  AN_OUT	: out std_logic_vector(3 downto 0);
			  CA_OUT	: OUT std_logic_vector(7 downto 0);
			  Reset_IN : in STD_LOGIC);
end MAIN;

architecture Behavioral of MAIN is

COMPONENT Seg
	PORT(
		Clock_In : IN std_logic;
		Data_In : IN std_logic_vector(7 downto 0);
		Addr_In : IN std_logic_vector(4 downto 0);
		CS_In : IN std_logic;          
		AN : OUT std_logic_vector(3 downto 0);
		Data_Out : OUT std_logic_vector(7 downto 0);
		RESET_IN : IN std_logic; 
		CA : OUT std_logic_vector(7 downto 0)
		);
	END COMPONENT;

COMPONENT tx_uart
	PORT(
		TX_REG_8_BIT_IN : IN std_logic_vector(7 downto 0);
		CLOCK_IN : IN std_logic;
		RESET_IN : IN std_logic;
		WR_EN : IN std_logic;          
		TX_OUT : OUT std_logic;
		TICKSIGNAL_IN : in STD_LOGIC;
		WR_READY_OUT : OUT std_logic
		);
	END COMPONENT;

COMPONENT rx_uart
	PORT(
		RX_IN : IN std_logic;
		CLOCK_IN : IN std_logic;
		RESET_IN : IN std_logic;          
		FIFO_18_BIT_OUT : OUT std_logic_vector(17 downto 0);
		READ_MESSAGE_IN : IN std_logic;
		MESSAGE_READY_OUT : OUT std_logic;
		VALID_OUT : OUT std_logic;
		TICKSIGNAL_OUT : OUT std_logic
		);
	END COMPONENT;
	
	COMPONENT Clock_29MHZ
	PORT(
		CLKIN_IN        : in    std_logic; 
          RST_IN          : in    std_logic; 
          CLKFX_OUT       : out   std_logic; 
          CLKIN_IBUFG_OUT : out   std_logic; 
          CLK0_OUT        : out   std_logic; 
          LOCKED_OUT      : out   std_logic
		);
	END COMPONENT;
	
	COMPONENT led_control
	PORT(
		Data_In : IN std_logic_vector(7 downto 0);
		Data_Out : OUT std_logic_vector(7 downto 0);
		CS_In : IN std_logic;
		Clock_In : IN std_logic;       
		RESET_IN : IN std_logic; 		
		Addr_In : IN std_logic_vector(4 downto 0);
		Led_Out : OUT std_logic_vector(7 downto 0)
		);
	END COMPONENT;
	
	
	
--constants
constant MID1 : std_logic_vector(15 downto 0) := x"0001";
constant LED_MSG_BYTE_COUNT : std_logic_vector(15 downto 0) := x"000C"; 
constant SEG_MSG_BYTE_COUNT : std_logic_vector(15 downto 0) := x"000C"; 

--TX signals
signal transmit : std_logic_vector(7 downto 0) := "00000000"; --Send char '1'
signal wrr : std_logic;
signal wrr_ready : std_logic;

--RX signals
signal rdd : std_logic := '0';
signal rdd_ready : std_logic;
signal receive : std_logic_vector(17 downto 0) := "000000000000000000";
signal message_id_reg : std_logic_vector(15 downto 0);
signal byte_count_reg : std_logic_vector(15 downto 0);
signal ticksignal_s : std_logic;

signal clock_ref : std_logic;
signal clock_reset : std_logic; --must assert for 3 clock cycles
signal cnt : std_logic_vector(2 downto 0) := "000";

--FIFO
--signal din : std_logic_vector(15 downto 0);
signal end_msg : std_logic;          
--signal dout : std_logic_vector(15 downto 0);
signal valid_in : std_logic;
signal empty_in : std_logic;
signal lower_byte :std_logic := '0';
signal set_lower_byte :std_logic := '0';
signal reset_lower_byte :std_logic := '0';

--CONTROL
signal data_in_bus : std_logic_vector(7 downto 0) := "00000000";
signal data_out_bus : std_logic_vector(7 downto 0) := "00000000";
signal address_bus : std_logic_vector(4 downto 0) := "00000";
signal led_cs: std_logic;
signal seg_cs: std_logic;

--LED
signal led_sig : std_logic_vector(7 downto 0);
signal led_start : std_logic := '0';
signal led_data_out_bus : std_logic_vector(7 downto 0) := "00000000";

--Seven Segment
signal seg_data_out_bus : std_logic_vector(7 downto 0) := "00000000";
signal seg_start : std_logic := '0';
signal segment_value : std_logic_vector(7 downto 0) := "00000000";

type mainState is (
		MAIN_Idle,
		MAIN_Fifo0,
		MAIN_Fifo1,
		MAIN_Fifo2,
		MAIN_Finish0
		);
		
signal main_current	:	mainState := MAIN_Idle;
	
type msgState is (
		MSG_Idle,
		LED_Read0,
		--LED_Read1,
		LED_Write0,
		LED_Write1,
		SEG_Read0,
		SEG_Read1,
		SEG_Write0,
		SEG_Write1,
		SEG_Write2
				);
		
signal msg_current	:	msgState := MSG_Idle;


begin
					
	Inst_tx_uart: tx_uart PORT MAP(
		TX_OUT => Serial_Out,
		TX_REG_8_BIT_IN => transmit,
		CLOCK_IN => clock_ref,
		RESET_IN => RESET_IN,
		WR_EN =>  wrr,
		TICKSIGNAL_IN => ticksignal_s,
		WR_READY_OUT => wrr_ready
	);
	
	Inst_rx_uart: rx_uart PORT MAP(
		RX_IN => Serial_In,
		FIFO_18_BIT_OUT => receive,
		CLOCK_IN => clock_ref,
		MESSAGE_READY_OUT => rdd_ready,
		READ_MESSAGE_IN => rdd,
		TICKSIGNAL_OUT => ticksignal_s,
		VALID_OUT => valid_in,
		RESET_IN => RESET_IN
	);
	
	Inst_clock_29_MHZ: Clock_29MHZ PORT MAP(
		CLKIN_IN  => CLOCK_IN,     
		RST_IN  => '0',       
		CLKFX_OUT  => clock_ref ,   
		CLKIN_IBUFG_OUT => open,
		CLK0_OUT  => open,     
		LOCKED_OUT  => open   
	);
	
	Inst_led_control: led_control PORT MAP(
		Data_In => data_in_bus,
		Data_Out => led_data_out_bus,
		Addr_In => address_bus,
		CS_In => led_cs,
		Clock_In => clock_ref,
		RESET_IN => RESET_IN,
		Led_Out => led_sig
	);
	
	Inst_Seg: Seg PORT MAP(
		AN => AN_OUT,
		Clock_In => clock_ref,
		Data_In => data_in_bus,
		Data_Out => seg_data_out_bus,
		Addr_In => address_bus,
		CS_In => seg_cs,
		RESET_IN => RESET_IN,
		CA => CA_OUT
	);

LED <= led_sig;

process (clock_ref)
	begin
	
	if rising_edge(clock_ref) then
		wrr <= '0';
		end_msg <= '0';
		set_lower_byte <= '0';
		reset_lower_byte <= '0';
		
		
		led_start <= '0';
		seg_start <= '0';
		
		if(receive(17) = '1') then
			end_msg <= '1';
		end if;
		
		--set that we are sending lower byte
		if(set_lower_byte = '1') then
			lower_byte <= '1';
		elsif(reset_lower_byte = '1') then
			lower_byte <= '0';
		end if;
		
		if(RESET_In = '1') then
			main_current <= MAIN_Idle;
		end if;
		
		case main_current is					
			when MAIN_Idle =>
				rdd <= '0';
				if(rdd_ready = '1') then
					main_current <= MAIN_Fifo0;
				else
					main_current <= MAIN_Idle;
				end if;
			when MAIN_Fifo0 =>
				rdd <= '1';
				main_current <= MAIN_Fifo1;
			when MAIN_Fifo1 =>
				main_current <= MAIN_Fifo1;
				rdd <= '1';
				if(valid_in = '1' and receive(16) = '1') then
					message_id_reg <= receive(15 downto 0);
					main_current <= MAIN_Fifo2;
				end if;
			when MAIN_Fifo2 =>
				main_current <= MAIN_Fifo2;
				rdd <= '1';
				if(valid_in = '1') then
					byte_count_reg <= receive(15 downto 0);
					main_current <= MAIN_Finish0;
					if(message_id_reg = x"0100") then --led message
						led_start <= '1';
					elsif(message_id_reg = x"0110") then --seven segment message
						seg_start <= '1';
					end if;
				end if;
			when MAIN_Finish0 =>
				rdd <= '1';
				main_current <= MAIN_Finish0;
				if(end_msg = '1') then
					rdd <= '0';
					main_current <= MAIN_Idle;
				end if;
			when others =>
				rdd <= '0';
				main_current <= MAIN_Idle;
		end case;
	end if;
end process;

--LED test process

--led_cs <= '1' when (chip_address = "001") else '0';

--address_bus <= 

--Read Message State Machine
process(clock_ref)
begin
	if rising_edge(clock_ref) then
		led_cs <= '0';
		seg_cs <= '0';
		address_bus <= "00000";
		data_in_bus <= x"00";
		
		case msg_current is 
			when MSG_Idle =>
				msg_current <= MSG_Idle;
				
				-----------------LED Command MESSAGE-----------------
				--
				--Byte[0:1] - MsgId [Handled in MSG_Idle state]
				--Byte[2:3] - Byte Count
				--Byte[4:5] - Led Mode 
				--Byte[6:7] - Led Value
				--Byte[8:9] - Spare
				--Byte[10:11] - Spare
				if(led_start = '1') then
					if(byte_count_reg = LED_MSG_BYTE_COUNT) then
						msg_current <= LED_Write0;
						led_cs <= '1';
						address_bus(4 downto 0) <= "00001"; --specify mode register
						data_in_bus <= receive(7 downto 0); 
					end if;
				-----------------7 Segment Command MESSAGE-----------------
				--
				--Byte[0:1] - MsgId [Handled in MSG_Idle state]
				--Byte[2:3] - Byte Count
				--Byte[4:5] - 7 SEgment Mode 
				--Byte[6:7] - Segment Value
				--Byte[8:9] - Segment DP Value
				--Byte[10:11] - Spare
				elsif (seg_start = '1') then
					if(byte_count_reg = SEG_MSG_BYTE_COUNT) then
						msg_current <= SEG_Write0;
						seg_cs <= '1';
						address_bus(4 downto 0) <= "00001"; --specify mode register
						data_in_bus <= receive(7 downto 0); --specify mode value
					end if;
				end if;
			-----------------LED MESSAGE-----------------			
			when LED_Write0 =>
				msg_current <= LED_Write0;
				if(valid_in = '1') then					
					address_bus(4 downto 0) <= "00010"; --specify value register
					data_in_bus <= receive(7 downto 0); -- specify led value	
					led_cs <= '1';
					msg_current <= MSG_Idle;
				end if;
			when LED_Read0 =>
				msg_current <= LED_Read0;
				if(valid_in = '1') then					
					address_bus(4 downto 0) <= receive(4 downto 0); --specify value register
					data_in_bus <= receive(15 downto 8); -- specify value	
					led_cs <= '1';
					msg_current <= MSG_Idle;
				end if;
			when SEG_Write0 =>
				msg_current <= SEG_Write0;
				if(valid_in = '1') then					
					address_bus(4 downto 0) <= "00010"; --specify value lo register
					data_in_bus <= receive(7 downto 0); -- specify value
					--data_in_bus <= "01101001"; -- specify value
					segment_value <= receive(15 downto 8); -- specify mode value
					seg_cs <= '1';
					msg_current <= SEG_Write1;
				end if;
			when SEG_Write1 =>
				msg_current <= SEG_Write1;
				if(valid_in = '1') then					
					address_bus(4 downto 0) <= "00011"; --specify value hi register
					data_in_bus <= segment_value; -- specify mode value	
					--data_in_bus <= "11000011"; -- specify mode value	
					segment_value <= receive(7 downto 0); -- specify dp value
					seg_cs <= '1';
					msg_current <= SEG_Write2;
				end if;
			when SEG_Write2 =>
				msg_current <= SEG_Write2;
				if(valid_in = '1') then					
					address_bus(4 downto 0) <= "00100"; --specify mode register
					data_in_bus <= segment_value; -- specify mode value
					--data_in_bus <= "00001100";
					seg_cs <= '1';
					msg_current <= MSG_Idle;
				end if;
			when SEG_Read0 =>
				msg_current <= SEG_Read0;
				if(valid_in = '1') then					
					address_bus(4 downto 0) <= receive(4 downto 0); --specify value register
					data_in_bus <= receive(15 downto 8); -- specify value	
					seg_cs <= '1';
					msg_current <= MSG_Idle;
				end if;
			when others =>
				msg_current <= MSG_Idle;
			
				
		end case;
	end if; --clock_ref
end process;
		
end Behavioral;

